home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
networke
/
civ-0.000
/
civ-0
/
civ-0.3
/
src
/
units.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-15
|
11KB
|
503 lines
#include <string.h>
#include "misc.h"
#include "defs.h"
#include "world.h"
#include "display.h"
#include "trans.h"
#include "units.h"
#include "move.h"
#include "city.h"
#include "player.h"
#include "MsgQ.h"
#include "rules.h"
#include "savefile.h"
#include "../pic/armor.xpm"
#include "../pic/artillery.xpm"
#include "../pic/battleship.xpm"
#include "../pic/bomber.xpm"
#include "../pic/cannon.xpm"
#include "../pic/caravan.xpm"
#include "../pic/carrier.xpm"
#include "../pic/catapult.xpm"
#include "../pic/cavalry.xpm"
#include "../pic/chariot.xpm"
#include "../pic/cruiser.xpm"
#include "../pic/diplomat.xpm"
#include "../pic/fighter.xpm"
#include "../pic/frigate.xpm"
#include "../pic/ironclad.xpm"
#include "../pic/knights.xpm"
#include "../pic/legion.xpm"
#include "../pic/mechinf.xpm"
#include "../pic/militia.xpm"
#include "../pic/musketeers.xpm"
#include "../pic/nuclear.xpm"
#include "../pic/phalanx.xpm"
#include "../pic/riflemen.xpm"
#include "../pic/sail.xpm"
#include "../pic/settler.xpm"
#include "../pic/submarine.xpm"
#include "../pic/transport.xpm"
#include "../pic/trireme.xpm"
char *names[] = {
"Armor",
"Artillery",
"Battleship",
"Bomber",
"Cannon",
"Caravan",
"Carrier",
"Catapult",
"Cavalry",
"Chariot",
"Cruiser",
"Diplomat",
"Fighter",
"Frigate",
"Ironclad",
"Knights",
"Legion",
"Mech. Infantry",
"Militia",
"Musketeers",
"Nuclear",
"Phalanx",
"Riflemen",
"Sail",
"Settlers",
"Submarine",
"Transport",
"Trireme"
};
char **pictures[] = {
armor_xpm,
artillery_xpm,
battleship_xpm,
bomber_xpm,
cannon_xpm,
caravan_xpm,
carrier_xpm,
catapult_xpm,
cavalry_xpm,
chariot_xpm,
cruiser_xpm,
diplomat_xpm,
fighter_xpm,
frigate_xpm,
ironclad_xpm,
knights_xpm,
legion_xpm,
mechinf_xpm,
militia_xpm,
musketeers_xpm,
nuclear_xpm,
phalanx_xpm,
riflemen_xpm,
sail_xpm,
settler_xpm,
submarine_xpm,
transport_xpm,
trireme_xpm
};
int admList[] = {
10, 5, 3, // armor
12, 2, 2, // artillery
18, 12, 4,// battleship
12, 1, 8, // bomber
8, 1, 1, // cannon
0, 1, 1, // caravan
1, 12, 5, // carrier
6, 1, 1, // catapult
2, 1, 2, // cavalry
4, 1, 2, // chariot
6, 6, 6, // cruiser
0, 0, 2, // diplomat
4, 2, 10, // fighter
2, 2, 3, // frigate
4, 4, 4, // ironclad
4, 2, 2, // knights
3, 1, 1, // legion
6, 6, 3, // mech. inf
1, 1, 1, // militia
2, 3, 1, // musketeers
99, 0, 16,// nuclear
1, 2, 1, // phalanx
3, 5, 1, // riflemen
1, 1, 3, // sail
0, 1, 1, // settlers
8, 2, 3, // submarine
0, 3, 4, // transport
1, 0, 3 // trireme
};
long *Unit::compiledPicsArray[MaxUnits];
char **Unit::Picture()
{
return pictures[type];
}
int SeaUnit(int type)
{
switch (type) {
case BATTLESHIP:
case CARRIER:
case CRUISER:
case FRIGATE:
case IRONCLAD:
case SAIL:
case SUBMARINE:
case TRANSPORT:
case TRIREME:
return 1;
}
return 0;
}
int AirUnit(int type)
{
switch (type) {
case FIGHTER:
case BOMBER:
return 1;
}
return 0;
}
int UnitVisibility(int type)
{
switch (type) {
case CARRIER:
case BATTLESHIP:
case BOMBER:
case CRUISER:
case SUBMARINE:
return 2;
}
return 1;
}
int UnitAttack(int type)
{
return admList[type*3];
}
int UnitDefense(int type)
{
return admList[type*3+1];
}
int UnitMoves(int type)
{
return admList[type*3+2];
}
int SettlerOrder(Unit *u, int key)
{
City *city;
switch (key) {
case 'b': // build city
if (world->WhichCity(u->x, u->y) != 0) return 1;
city = new City(strdup(*cityNames++), trans->New(), u->x, u->y, playerId);
// city counts as road automatically:
world->MakeRoad(u->x, u->y);
// auto-irrigate on city square if it is 'clear' type terrain:
switch (world->Terrain(u->x, u->y)) {
case GRASS1:
case GRASS:
case PLAINS:
case RIVER:
world->Irrigate(u->x, u->y);
}
*moveQ << PieceMove(city->id, CITY_CREATE, u->x, u->y);
*moveQ << city->name;
*moveQ << PieceMove(u->id, PIECE_DIE, 0, 0);
return 0; // we died
case 'i': // irrigate
if ((u->orderProgress = world->IrrigTime(u->x, u->y)) > 0) {
u->currOrder = 'i';
u->numMoves = 0;
}
break;
case 'p': // unPollute
if ((u->orderProgress = world->UnPolluteTime(u->x, u->y)) > 0) {
u->currOrder = 'p';
u->numMoves = 0;
}
break;
case 'r': // road
if (world->IsRailRoad(u->x, u->y)) break; // can't do more
if (world->IsRoad(u->x, u->y)) { // try to build railroad
if (Discovered(u->ownerId, "Railroad") &&
(u->orderProgress = world->RailRoadTime(u->x, u->y)) > 0) {
u->currOrder = 'r';
u->numMoves = 0;
}
break;
}
if (world->Terrain(u->x, u->y) == RIVER &&
!Discovered(u->ownerId, "Bridge Building")) break;
if ((u->orderProgress = world->RoadTime(u->x, u->y)) > 0) {
u->currOrder = 'r';
u->numMoves = 0;
}
break;
case 'm':
if (world->Mined(u->x, u->y)) break; // can't do more
if ((u->orderProgress = world->MineTime(u->x, u->y)) > 0) {
Debug('u',"Mining at %d %d (%d turns)", u->x, u->y, u->orderProgress);
u->currOrder = 'm';
u->numMoves = 0;
}
break;
}
return 1;
}
void SettlerCompleteOrder(Unit *u)
{
switch (u->currOrder) {
case 'i':
if (--u->orderProgress <= 0) {
world->Irrigate(u->x, u->y);
u->currOrder = ' ';
}
u->numMoves = 0;
break;
case 'p':
if (--u->orderProgress <= 0) {
world->UnPollute(u->x, u->y);
u->currOrder = ' ';
}
u->numMoves = 0;
break;
case 'r':
if (--u->orderProgress <= 0) {
if (world->IsRoad(u->x, u->y)) {
if (Discovered(u->ownerId, "Railroad"))
world->MakeRailRoad(u->x, u->y);
}
else world->MakeRoad(u->x, u->y);
u->currOrder = ' ';
}
u->numMoves = 0;
break;
case 'm':
if (--u->orderProgress <= 0) {
world->Mine(u->x, u->y);
u->currOrder = ' ';
}
u->numMoves = 0;
break;
}
}
Unit *NewUnit(int type, int owner, ulong id, int vet, ulong city, int x, int y)
{
Debug('u', "Creating new Unit id %ld, owner %d, at %d %d\n", id, owner, x, y);
Unit *unit = new Unit(owner, id, vet, city, x, y, type);
trans->SetPtr(unit->id, unit);
Debug('u', "Doing display for new Unit\n");
if (owner == playerId) {
display->ShowPiece(unit->x, unit->y, unit->id);
world->SeeSquare(unit->x, unit->y, unit->Visibility());
}
else
unit->DrawIfVisible();
Debug('u', "Done NewUnit for new Unit\n");
return unit;
}
int Unit::Order(int key)
{
if (key == 'f') {
currOrder = 'f';
numMoves = 0;
}
else if (key == 's') {
currOrder = 's';
numMoves = 0;
}
else if (key == ' ')
numMoves = 0;
else if (key == 'd') {
if (type == CARAVAN) {
City *city = trans->TransCity(world->WhichCity(x,y));
if (city) city->accProd += 50;
}
*moveQ << PieceMove(this->id, PIECE_DIE, 0, 0);
return 0; // we died
}
else if (key == 'u' && carrying) { // wake up cargo
for (Lister<ulong> l = carrying; l; l.Next()) {
Unit *ptr = trans->TransUnit(l.Elem());
ptr->currOrder = ' ';
ptr->numMoves = UnitMoves(ptr->type);
}
}
else {
switch (type) {
case SETTLER:
return SettlerOrder(this, key);
}
}
return 1;
}
void Unit::CompleteOrder()
{
if (currOrder == 'f') {
if (!Fortified()) {
Fortify();
DrawIfVisible();
*moveQ << PieceMove(id, UNIT_UPDATE, 1, Veteran() ? 1 : 0);
}
numMoves = 0;
}
else if (currOrder == 's') // asleep
numMoves = 0;
else {
switch (type) {
case SETTLER:
SettlerCompleteOrder(this);
}
}
}
int Unit::CanMoveOn(int terrainType, int dx, int dy)
{
// can always move into a city
// FIXME: actually ought not be able to move seaunits into enemy city
if (world->WhichCity(dx, dy) != 0 || type == NUCLEAR) return 1;
if (SeaUnit(type)) return terrainType == WATER;
if (AirUnit(type)) return 1;
if (terrainType == WATER) { // check if there is a carrier unit
// land unit can't move from carrier to carrier
// so if its already carried fail
// FIXME? This looks as if it doesnt care whether carrier is your own?!
if (carriedBy != 0) return 0;
for (Lister<ulong> unitl = world->Units(dx, dy); unitl; unitl.Next()) {
Unit *unit = trans->TransUnit(unitl.Elem());
if (unit->CanCarry(this))
return 1;
}
return 0;
}
return 1;
}
int Unit::CanAttack(int type)
{
// sea units can attack other sea units
// battleships, cruisers, ironclads, frigates can attack coastal units
switch (type) {
case BATTLESHIP:
case IRONCLAD:
case FRIGATE:
case CRUISER:
if (AirUnit(type) || type == NUCLEAR) return 0;
return 1;
case CARRIER:
case SAIL:
case SUBMARINE:
case TRIREME:
case TRANSPORT:
return SeaUnit(type);
case FIGHTER:
return type == BOMBER;
case BOMBER: // can attack anything except a nuclear or fighter
if (AirUnit(type) || type == NUCLEAR) return 0;
return 1;
}
if (AirUnit(type) || SeaUnit(type) || type == NUCLEAR || carriedBy != 0)
return 0;
return 1;
}
double Unit::MoveCost(int terrainType, double movesRem, int sx, int sy,
int dx, int dy)
{
if (SeaUnit(type) || AirUnit(type)) return 1;
double cost;
if (world->IsRoad(dx, dy))
cost = 0.333333334;
else if (world->IsRailRoad(dx, dy))
cost = 0;
else {
switch (terrainType) {
case MOUNTAINS:
cost = 3; break;
case SWAMP:
case HILLS:
case FOREST:
case JUNGLE:
cost = 2; break;
case DESERT:
case PLAINS:
case GRASS:
case GRASS1:
case RIVER:
cost = 1; break;
case WATER:
cost = movesRem;
break;
default:
cost = 1;
break;
}
}
if ((cost > 1.50001*movesRem) && (movesRem < Moves(players[playerId]->seamoveBonus))) {
return -1.0; // can't move, too high cost
}
return cost;
}
int Unit::CanCarry(Unit *unit)
{
if (unit->ownerId != ownerId) return 0;
int carryNum = 0, destType = unit->type;
switch (type) {
case CARRIER:
return (AirUnit(destType) || destType == NUCLEAR) && carrying.Count() < 12;
case FRIGATE:
carryNum = 4; break;
case SAIL:
carryNum = 3; break;
case TRANSPORT:
carryNum = 8; break;
case TRIREME:
carryNum = 2; break;
}
return carryNum > 0 && !AirUnit(destType) && !SeaUnit(destType) &&
destType != NUCLEAR && carrying.Count() < carryNum;
}
void Unit::SetCoord(int xc, int yc)
{
x = xc;
y = yc;
for (Lister<ulong> l = carrying; l; l.Next())
trans->TransUnit(l.Elem())->SetCoord(x, y);
}
void Unit::Save()
{
WriteULong(id);
WriteULong(cityId);
WriteULong(carriedBy);
WriteUChar(flags);
WriteUChar(ownerId);
WriteUShort(x);
WriteUShort(y);
WriteUChar(type);
WriteUChar(currOrder);
WriteUShort(orderProgress);
WriteUShort(carrying.Count());
for (Lister<ulong> l = carrying; l; l.Next())
WriteULong(l.Elem());
}